package com.hadluo.qq.server.websocket;

import com.alibaba.fastjson.JSON;
import com.hadluo.qq.server.config.WebSocketConfig;
import com.hadluo.qq.server.entity.GroupMember;
import com.hadluo.qq.server.entity.GroupMessage;
import com.hadluo.qq.server.entity.Message;
import com.hadluo.qq.server.entity.User;
import com.hadluo.qq.server.service.GroupMessageService;
import com.hadluo.qq.server.service.GroupService;
import com.hadluo.qq.server.service.MessageService;
import com.hadluo.qq.server.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket处理类
 * @author hadluo
 */
@Slf4j
@Component
@ServerEndpoint(value = "/ws/{userId}")
public class ChatWebSocket {
    // 设置WebSocket消息大小限制为10MB
    private static final int MAX_MESSAGE_SIZE = 10 * 1024 * 1024;

    @Autowired
    private static MessageService messageService;

    @Autowired
    private static GroupMessageService groupMessageService;


    @Autowired
    private static GroupService groupService;


    @Autowired
    private static UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        ChatWebSocket.userService = userService;
    }

    @Autowired
    public  void setGroupService(GroupService groupService) {
        ChatWebSocket.groupService = groupService;
    }

    @Autowired
    public  void setGroupMessageService(GroupMessageService groupMessageService) {
        ChatWebSocket.groupMessageService = groupMessageService;
    }

    @Autowired
    public void setMessageService(MessageService messageService) {
        ChatWebSocket.messageService = messageService;
    }

    /**
     * 用于存储当前在线用户的WebSocket连接
     * key: userId
     * value: WebSocket session
     */
    private static final Map<String, Session> onlineUsers = new ConcurrentHashMap<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        // 检查是否已经登录
        if (onlineUsers.containsKey(userId)) {
            try {
                // 发送重复登录错误消息
                String errorMessage = JSON.toJSONString(new HashMap<String, Object>() {{
                    put("type", "ERROR");
                    put("code", "DUPLICATE_LOGIN");
                    put("message", "该账号已在其他设备登录");
                }});
                session.getBasicRemote().sendText(errorMessage);
                session.close();
                return;
            } catch (IOException e) {
                log.error("发送重复登录错误消息失败", e);
            }
        }

        onlineUsers.put(userId, session);
        log.info("用户{}连接成功，当前在线人数：{}", userId, onlineUsers.size());
        // 广播用户上线消息
        broadcastUserStatus(userId, true);
    }

    @OnClose
    public void onClose(@PathParam("userId") String userId) {
        onlineUsers.remove(userId);
        log.info("用户{}断开连接，当前在线人数：{}", userId, onlineUsers.size());
        // 广播用户下线消息
        broadcastUserStatus(userId, false);
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("userId") String userId) {
        log.info("收到用户{}的消息：{}", userId, message);
        try {
            // 解析消息
            Map<String, Object> messageMap = JSON.parseObject(message);

            // 确保消息包含必要的字段
            if (!messageMap.containsKey("type")) {
                log.error("消息缺少type字段，原始消息：{}", message);
                return;
            }

            String type = (String) messageMap.get("type");
            log.info("处理用户{}的{}类型消息", userId, type);

            // 根据消息类型处理
            switch (type) {
                case "text":
                case "image":
                    if (!messageMap.containsKey("targetUserId") || !messageMap.containsKey("content")) {
                        log.error("聊天消息缺少必要字段，原始消息：{}", message);
                        return;
                    }

                    String targetUserId = messageMap.get("targetUserId").toString();
                    String content = messageMap.get("content").toString();
                    String msgtype = messageMap.get("type") != null ? messageMap.get("type").toString() : "text";
                    log.info("用户{}发送{}类型消息给用户{}，内容：{}", userId, type, targetUserId, content);

                    // 添加发送者信息和时间戳
                    messageMap.put("fromUserId", userId);
                    messageMap.put("timestamp", System.currentTimeMillis());

                    // 保存消息到数据库
                    Message dbMessage = new Message();
                    dbMessage.setSenderId(Long.parseLong(userId));
                    dbMessage.setReceiverId(Long.parseLong(targetUserId));
                    dbMessage.setContent(content);
                    dbMessage.setType(msgtype);
                    dbMessage.setCreateTime(new Date());
                    dbMessage.setStatus(0); // 未读状态
                    messageService.saveMessage(dbMessage);

                    // 发送消息给目标用户
                    String jsonMessage = JSON.toJSONString(messageMap);
                    log.info("转发消息到用户{}：{}", targetUserId, jsonMessage);
                    sendMessage(targetUserId, jsonMessage);
                    break;

                case "group-text":
                case "group-image":
                    // 处理群文本消息
                    if (!messageMap.containsKey("groupId") || !messageMap.containsKey("content")) {
                        log.error("群聊消息缺少必要字段，原始消息：{}", message);
                        return;
                    }

                    String groupId = messageMap.get("groupId").toString();

                    // 构建群消息对象
                    GroupMessage groupMessage = new GroupMessage();
                    groupMessage.setSenderId(Long.parseLong(userId));
                    groupMessage.setGroupId(Long.parseLong(groupId));
                    groupMessage.setContent(messageMap.get("content").toString());
                    if(type.contains("image")){
                        groupMessage.setType("image");
                    }else{
                        groupMessage.setType("text");
                    }
                    groupMessage.setStatus(0); // 未读状态

                    // 保存群消息到数据库
                    groupMessageService.saveGroupMessage(groupMessage);



                    // 获取群成员并转发消息
                    List<GroupMember> members = groupService.getGroupMembers(Long.parseLong(groupId));
                    for (GroupMember member : members) {
                        User u = userService.findById(member.getUserId()).get() ;
                        String memberUserId = u.getQqNumber() ;
                        // 不给发送者转发消息
                        if (!memberUserId.equals(userId)) {
                            // 添加发送者信息和时间戳到消息
                            messageMap.put("fromUserId", userId);
                            messageMap.put("timestamp", System.currentTimeMillis());
                            String jsonGroupMessage = JSON.toJSONString(messageMap);
                            messageMap.put("user",u);
                            sendMessage(memberUserId, jsonGroupMessage);
                        }
                    }
                    break;

                case "heartbeat":
                    // 心跳消息，直接返回
                    log.debug("收到用户{}的心跳消息", userId);
                    session.getBasicRemote().sendText("{\"type\":\"heartbeat\",\"status\":\"ok\"}");
                    break;
                case "shake":
                    if (!messageMap.containsKey("targetUserId")) {
                        log.error("抖动消息缺少必要字段，原始消息：{}", message);
                        return;
                    }

                    String targetUserId1 = messageMap.get("targetUserId").toString();
                    log.info("用户{}发送抖动消息给用户{}", userId, targetUserId1);

                    // 添加发送者信息和时间戳
                    messageMap.put("fromUserId", userId);
                    messageMap.put("timestamp", System.currentTimeMillis());

                    // 发送抖动消息给目标用户
                    String jsonMessage1 = JSON.toJSONString(messageMap);
                    log.info("转发抖动消息到用户{}：{}", targetUserId1, jsonMessage1);
                    sendMessage(targetUserId1, jsonMessage1);
                    break;

                default:
                    log.warn("收到未知类型的消息：type={}，userId={}，message={}", type, userId, message);
            }
        } catch (Exception e) {
            log.error("处理用户{}的消息时发生错误，原始消息：{}", userId, message, e);
        }
    }

    /**
     * 发生错误时调用的方法
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket发生错误", error);
    }

    /**
     * 发送消息给指定用户
     */
    public void sendMessage(String userId, String message) {
        Session session = onlineUsers.get(userId);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
                log.info("成功发送消息给用户{}：{}", userId, message);
            } catch (IOException e) {
                log.error("发送消息给用户{}失败：{}", userId, message, e);
            }
        } else {
            log.warn("发送消息，用户{}不在线，消息内容：{}", userId, message);
        }
    }

    /**
     * 广播消息给所有在线用户
     */
    public void broadcastMessage(String message) {
        log.info("开始广播消息：{}", message);
        int successCount = 0;
        int failCount = 0;
        for (Map.Entry<String, Session> entry : onlineUsers.entrySet()) {
            try {
                entry.getValue().getBasicRemote().sendText(message);
                successCount++;
            } catch (IOException e) {
                failCount++;
                log.error("广播消息给用户{}失败", entry.getKey(), e);
            }
        }
        log.info("广播消息完成，成功：{}，失败：{}", successCount, failCount);
    }

    /**
     * 广播用户状态变更消息
     */
    private void broadcastUserStatus(String userId, boolean online) {
        String statusMessage = JSON.toJSONString(new HashMap<String, Object>() {{
            put("type", "STATUS");
            put("userId", userId);
            put("online", online);
            put("timestamp", System.currentTimeMillis());
        }});
        broadcastMessage(statusMessage);
    }

    /**
     * 获取当前在线用户数量
     */
    public static int getOnlineCount() {
        return onlineUsers.size();
    }

    /**
     * 判断用户是否在线
     */
    public static boolean isUserOnline(String userId) {
        return onlineUsers.containsKey(userId);
    }
}